Add support for CRSes not in the EPSG database#1816
Add support for CRSes not in the EPSG database#1816pierotofy merged 7 commits intoOpenDroneMap:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds support for handling Coordinate Reference Systems (CRSes) that lack EPSG codes by storing georeferencing information as Well-Known Text (WKT) when an EPSG code is unavailable.
Key Changes:
- Added a new
wktfield to the Task model to store WKT definitions for non-EPSG CRSes - Updated georeferencing logic to prefer EPSG codes but fall back to WKT when necessary
- Modified UI components to display CRS information from either EPSG or WKT sources
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| package.json | Version bumped to 3.1.0 |
| locale | Updated subproject commit reference |
| app/tests/test_task_wkt.py | New test case validating WKT-based georeferencing |
| app/tests/test_api_task.py | Added assertion to verify WKT is null when EPSG exists |
| app/static/app/js/translations/odm_autogenerated.js | Reordered translation strings (auto-generated) |
| app/static/app/js/css/TaskListItem.scss | Added styles for task ID copy-to-clipboard feature |
| app/static/app/js/components/TaskListItem.jsx | Enhanced UI to show task ID with copy functionality and display CRS information |
| app/static/app/js/components/ExportAssetPanel.jsx | Updated export panel to handle both EPSG and WKT for CRS selection |
| app/models/task.py | Added wkt field and updated georeferencing methods to support WKT |
| app/migrations/0047_task_wkt.py | Database migration adding the wkt field |
| app/geoutils.py | Enhanced utility functions to work with both EPSG codes and WKT |
| app/api/tiler.py | Updated tiler API to include WKT in bounds information |
| app/api/tasks.py | Modified task serializer to use WKT-aware helper functions |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (!this._clipboardTimeout){ | ||
| clearTimeout(this._clipboardTimeout); | ||
| this._clipboardTimeout = null; | ||
| } | ||
| setTimeout(() => { | ||
| this.setState({copiedToClipboard: false}); |
There was a problem hiding this comment.
The condition is inverted - it should be if (this._clipboardTimeout) instead of if (!this._clipboardTimeout). Currently, the code only clears the timeout when it doesn't exist, which is the opposite of the intended behavior.
| if (!this._clipboardTimeout){ | |
| clearTimeout(this._clipboardTimeout); | |
| this._clipboardTimeout = null; | |
| } | |
| setTimeout(() => { | |
| this.setState({copiedToClipboard: false}); | |
| if (this._clipboardTimeout){ | |
| clearTimeout(this._clipboardTimeout); | |
| this._clipboardTimeout = null; | |
| } | |
| this._clipboardTimeout = setTimeout(() => { | |
| this.setState({copiedToClipboard: false}); | |
| this._clipboardTimeout = null; |
| if epsg is not None: | ||
| if srs.ImportFromEPSG(epsg) != 0: | ||
| return {'name': '', 'units': 'm'} | ||
|
|
||
| if wkt is not None: | ||
| if srs.ImportFromWkt(wkt) != 0: | ||
| return {'name': '', 'units': 'm'} |
There was a problem hiding this comment.
When both epsg and wkt are provided, the function imports epsg first but then overwrites the srs object with wkt. This can lead to incorrect results if epsg import succeeds but wkt import fails or vice versa. The logic should use elif for the wkt check, or handle the case where both are provided differently.
| } | ||
|
|
||
| if (epsg == projEPSG) title = projSrsName; | ||
| else if (epsg == "" && projWKT) title = projWKT; |
There was a problem hiding this comment.
Use strict equality operators (===) instead of loose equality (==) for comparisons. This is especially important when comparing with empty strings.
| else if (epsg == "" && projWKT) title = projWKT; | |
| else if (epsg === "" && projWKT) title = projWKT; |
| proj = srs.ExportToProj4() | ||
| if proj is not None and proj != "": | ||
| name = proj | ||
| except: |
There was a problem hiding this comment.
Bare except clause catches all exceptions including system exits and keyboard interrupts. Specify the exception type(s) to catch, such as except Exception: or more specific exception types.
| except: | |
| except Exception: |

Some CRSes do not have EPSG codes, which WebODM does not handle correctly.
This PR adds support for handling CRSes that don't have an explicit EPSG code by storing the georef information as WKT when an EPSG code is not available.